package com.leyou.item.service.impl;

import com.leyou.common.dto.PageDTO;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecGroupDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.client.ItemClient;
import com.leyou.item.entity.Goods;
import com.leyou.item.repository.GoodsRepository;
import com.leyou.item.service.SearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    GoodsRepository repository;

    @Autowired
    ItemClient itemClient;

    @Override
    public void createIndexAndMapping() {

        // 删除已经存在的索引库
        try {
            repository.deleteIndex();
        } catch (Exception e) {
            //log.error("删除失败，可能索引库不存在！", e);
        }
        repository.createIndex("{\n" +
                "  \"settings\": {\n" +
                "    \"analysis\": {\n" +
                "      \"analyzer\": {\n" +
                "        \"my_pinyin\": {\n" +
                "          \"tokenizer\": \"ik_smart\",\n" +
                "          \"filter\": [\n" +
                "            \"py\"\n" +
                "          ]\n" +
                "        }\n" +
                "      },\n" +
                "      \"filter\": {\n" +
                "        \"py\": {\n" +
                "\t\t  \"type\": \"pinyin\",\n" +
                "          \"keep_full_pinyin\": true,\n" +
                "          \"keep_joined_full_pinyin\": true,\n" +
                "          \"keep_original\": true,\n" +
                "          \"limit_first_letter_length\": 16,\n" +
                "          \"remove_duplicated_term\": true\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  },\n" +
                "  \"mappings\": {\n" +
                "    \"properties\": {\n" +
                "      \"id\": {\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"suggestion\": {\n" +
                "        \"type\": \"completion\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"title\":{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"image\":{\n" +
                "        \"type\": \"keyword\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"updateTime\":{\n" +
                "        \"type\": \"date\"\n" +
                "      },\n" +
                "      \"specs\":{\n" +
                "        \"type\": \"nested\",\n" +
                "        \"properties\": {\n" +
                "          \"name\":{\"type\": \"keyword\" },\n" +
                "          \"value\":{\"type\": \"keyword\" }\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "}\n");
    }

    @Override
    public void loadData() {
        int page = 1, rows = 50;
        while (true) {
            log.info("开始导入第{}页数据", page);
            // 分页查询已经上架的spu
            PageDTO<SpuDTO> result = itemClient.querySpuByPage(page, rows, true, null, null, null);
            List<SpuDTO> list = result.getItems();

            // 遍历Spu集合，把SpuDTO通过buildGoods方法转为Goods
            List<Goods> goodsList = list.stream()
                    .map(this::buildGoods).collect(Collectors.toList());


            // 批量写入Elasticsearch
            repository.saveAll(goodsList);
            log.info("导入第{}页数据结束。", page);
            // 翻页
            page++;

            // 获取总页数
            Long totalPage = result.getTotalPage();
            // 判断是否还有spu没有查询
            if (page > totalPage) {
                // 没有则结束
                break;
            }
        }
    }
    private Goods buildGoods(SpuDTO spuDTO) {
        Goods goods = new Goods();
        log.info(spuDTO.toString());
        BeanUtils.copyProperties(spuDTO,goods);

        //suggestion 候选值，主体名称，品牌+主体,品牌+分类，分类+品牌


        //侯选值的目的，就是满足搜索提示
        List<String> suggestList = new ArrayList<>();


        String goodsName = spuDTO.getName();
        String categoryName = spuDTO.getCategoryName().split("/")[2];
        String brandName = StringUtils.substringBefore(spuDTO.getBrandName(), "（");


        suggestList.add(goodsName);

        suggestList.add(goodsName.startsWith(brandName) ? brandName : brandName + goodsName);
        suggestList.add(brandName + categoryName);
        suggestList.add(categoryName + brandName);


        goods.setSuggestion(suggestList);
        // 2.sku的价格集合
        Set<Long> allPrice = itemClient
                .querySkuBySpuId(spuDTO.getId())
                .stream()
                .map(SkuDTO::getPrice)
                .collect(Collectors.toSet());
        goods.setPrices(allPrice);
        // 2.1.查询sku集合
        // 2.2.获取价格集合
        // 3.商品销量
        Long allSold = itemClient.querySkuBySpuId(spuDTO.getId())
                .stream()
                .map(SkuDTO::getSold)
                .reduce(0l, Long::sum);
        goods.setSold(allSold);
        // 4.sku的某个图片
        String images = itemClient.querySkuBySpuId(spuDTO.getId()).get(0).getImages();
        goods.setImage(images);
        // 5.规格参数
        // 5.1.查询规格参数name和value键值对，只查询参与搜索的
        Long categoryId = spuDTO.getCid3();
        List<Map> params = itemClient.querySpecsValues(categoryId, true)
                .stream()
                .map(SpecGroupDTO::getParams)
                .flatMap(list -> list.stream())
                .map(specParamDTO -> {
                    Map map = new HashMap();
                    map.put("name", specParamDTO.getName());
                    map.put("value", chooseSegment(specParamDTO));
                    return map;
                })
                .collect(Collectors.toList());


        // 5.2.封装
        goods.setSpecs(params);

        goods.setCategoryId(spuDTO.getCid3());

        return goods;
    }
    private Object chooseSegment(SpecParamDTO p) {
        Object value = p.getValue();
        if (value == null || StringUtils.isBlank(value.toString())) {
            return "其它";
        }
        if (!p.getNumeric() || StringUtils.isBlank(p.getSegments()) || value instanceof Collection) {
            return value;
        }
        double val = parseDouble(value.toString());
        String result = "其它";
        // 保存数值段
        for (String segment : p.getSegments().split(",")) {
            String[] segs = segment.split("-");
            // 获取数值范围
            double begin = parseDouble(segs[0]);
            double end = Double.MAX_VALUE;
            if (segs.length == 2) {
                end = parseDouble(segs[1]);
            }
            // 判断是否在范围内
            if (val >= begin && val < end) {
                if (segs.length == 1) {
                    result = segs[0] + p.getUnit() + "以上";
                } else if (begin == 0) {
                    result = segs[1] + p.getUnit() + "以下";
                } else {
                    result = segment + p.getUnit();
                }
                break;
            }
        }
        return result;
    }

    private double parseDouble(String str) {
        try {
            return Double.parseDouble(str);
        } catch (Exception e) {
            return 0;
        }
    }
}
